#include "players.h"
#include "units.h"



player::player( int i, string n, PlayerType t, bool real_pl )
{
	id = i;
	name = n;
	typ = t;
	time = parameters::get_instance()->game_parameters[ "START_TIME" ];
	in_game = true;
	real_player = real_pl;
};



player::~player()
{
	for( unsigned int i = 0; i < units.size(); ++i )
	{
		if ( real_player )
			mapa::get_instance()->set_object( 0,  units[ i ]->get_x(), units[ i ]->get_y() );
		delete units[ i ];
	}
	units.clear();
};



bool player::equals( player* p )
{
	if ( p == 0 )
		return false;
	if ( !( ( typ == p->get_type() ) &&
			( id == p->get_id() ) &&
			( name == p->get_name() ) &&
			( time == p->get_time() ) &&
			( in_game == p->is_in_game() ) &&
			( units.size() == p->units.size() ) ) )
	{
		return false;
	}
	if ( !( ( typ == ai ) && ( ai_algorithm->get_name() == p->ai_algorithm->get_name() ) ) )
		return false;
	for ( unsigned int u = 0; u < units.size(); ++u )
	{
		if ( !( units[ u ]->equals( p->units[ u ] ) ) )
			return false;
	}
	return true;
};



player* player::clone()
{
	player* p = new player( id, name, typ, false );
	p->set_time( time );
	for( unsigned int i = 0; i < units.size(); ++i )
	{
		unit* cu = dynamic_cast< unit* >( units[ i ]->clone() );
		cu->set_player( p );
		p->units.push_back( cu );
	}
	p->ai_algorithm = ai_algorithm;
	return p;
};



bool player::buy_unit( unit* u, unsigned int x, unsigned int y )
{
	pre_buy_info* pbi = new pre_buy_info( u, x, y );
	if ( ( int )u->get_price() > this->get_time() )
		return false;
	if ( dynamic_cast< object* >( mapa::get_instance()->get_object( x, y ) ) != 0 )
		return false;
	if ( mapa::get_instance()->terrain->get( x, y ) >= 20000 )
		return false;
	if ( units.size() >= parameters::get_instance()->game_parameters[ "MAX_UNITS" ] )
		return false;
	if ( ( int )mapa::get_instance()->terrain->get( x, y ) % 10 != ( id + 1 ) )
		return false;
	unit* nu = dynamic_cast< unit* >( u->clone() );
	units.push_back( nu );
	nu->init( x, y, this, ( units.size() + 1 ) );
	mapa::get_instance()->set_object( nu, x, y );
	this->set_time( get_time() - nu->get_price() );
	if ( game::get_instance()->get_current_player()->get_type() == local )
		game_gui::get_instance()->show_buy( nu, x, y, pbi );
	return true;
};



bool player::sell_unit( unsigned int n )
{
	if ( n >= units.size() )
		return false;
	vector< unit* >::iterator it = units.begin() + n;
	unit* u = *it;
	pre_sell_info* psi = new pre_sell_info( u );
	mapa::get_instance()->set_object( 0, u->get_x(), u->get_y() );
	this->set_time( get_time() + u->get_price() );
	delete u;
	units.erase( units.begin() + n );
	if ( get_type() == local )
		game_gui::get_instance()->show_sell( 0, psi );
	return true;
};



bool player::is_real()
{
	return real_player;
};



players* players::get_instance()
{
	static players inst( 0 );
	return &inst;
};



void players::fill_players()
{
	for ( unsigned int i = 0; i < parameters::get_instance()->game_parameters[ "MAX_PL" ]; ++i )
	{
		pl[ i ] = new player( -1, "", local );
	}
};



void players::set_player( player* p, unsigned int x )
{
	++players_count;
	
	if ( pl[ x ]->get_id() == -1 )
	{
		//player has some loaded units
		if ( !( pl[ x ]->units.empty() ) )
		{			
			//give those units to the player
			for ( unsigned int i = 0; i < pl[ x ]->units.size(); ++i )
			{
				unit* cu = pl[ x ]->units[ i ];
				mapa::get_instance()->set_object( cu, cu->get_x(), cu->get_y() );
				p->units.push_back( cu );
				cu->set_player( p );
				pl[ x ]->units[ i ] = 0;
			}
			pl[ x ]->units.clear();
		}
	}

	delete pl[ x ];
	pl[ x ] = p;
};



player* players::get_player( unsigned int x )
{
	return pl[ x ];
};



bool players::load_players( const char* file )
{
	ifstream fin;
	fin.open( file, ifstream::in );
	if ( !fin.good() )
	{
		cout << "ERROR WHILE OPENING PLAYERS FILE" << endl;
		fin.close();
		return false;
	}

	unsigned int num_players;

	fin >> num_players;
	string del;
	getline( fin, del );
	vector< string >* pl_cmds = new vector< string >( num_players );
	players* pla = players::get_instance();

	for( unsigned int i = 0; i < num_players; ++i )
	{	
		player* pl;
		string nm;
		getline( fin, nm );	
		PlayerType typ = ai;
		pl = new player( pla->get_players_count(), nm, typ );
		pla->set_player( pl, pla->get_players_count() );
		pl->ai_algorithm = ai_algorithms::get_instance()->algorithm_list[ "Replay" ]->clone();
		string commands;
		getline( fin, commands );
		( *pl_cmds )[ pl->get_id() ] = commands;
		if ( fin.fail() )
		{
			cout << "ERROR WHILE READING PLAYERS FILE" << endl;
			fin.close();
			delete pl_cmds;
			return false;
		}
	}
	for( unsigned int i = 0; i < num_players; ++i )
	{
		player* pl = pla->get_player( i );
		if ( !pl->ai_algorithm->init( pl, ( *pl_cmds )[ i ] ) )
		{
			cout << "ERROR WHILE READING PLAYERS FILE" << endl;
			fin.close();
			delete pl_cmds;
			return false;
		}
	}

	pl_cmds->clear();
	delete pl_cmds;
	fin.close();
	cout << "PLAYERS LOADED SUCCESSFULLY" << endl;
	return true;
};



void players::clean_players()
{
	for ( unsigned int i = 0; i < players_count; ++i )
	{
		pl[ i ]->set_in();
		for ( unsigned int j = 0; j < pl[ i ]->units.size(); ++j )
		{
			mapa::get_instance()->set_object( 0,  pl[ i ]->units[ j ]->get_x(), pl[ i ]->units[ j ]->get_y() );
			delete pl[ i ]->units[ j ];
		}
		pl[ i ]->units.clear();
	}
};